נושאים לשיעור זה: שאלת רענון בצירוף טבלאות פקודות :DDL מפתח ראשי Key( )Primary מפתח זר )חיצוני Key )Foreign o o סיכום הפקודות עד לשיעור זה SELECT id, count(id) + (S-Q) FROM Students AS S LEFT OUTER JOIN Course AS C, (S-Q) AS SQ ON S.studentID = C.studentID WHERE (id=3) AND (name is not NULL) AND X = (S-Q) GROUP BY id HAVING count(id) > 1 / count(id) = (S-Q) ORDER BY id, name *** )S-Q( = מקומות בהם ניתן לשלב תתי שאילתות 1
שאלת רענון בצירוף טבלאות: נתונות 2 טבלאות, מה יהיה הפלט ע"י הרצת 2 השאילתות הנ"ל? t1 a b 1 a 2 b t2 b c b 3 c 4 SELECT * FROM t1 LEFT JOIN t2 ON (t1.b = t2.b); a b b c 1 a Null Null 2 b b 3 לעומת זאת אם היינו מבצעים את הפקודה הבאה: SELECT * FROM t1 LEFT JOIN t2 ON (TRUE) WHERE (t1.b = t2.b); a b b c 2 b b 3 מתבצע צירוף חיצוני, כאשר כל השורות עומדות בתנאי הצירוף )כולם מקיימים את )TRUE ז"א שנקבל בעצם מכפלה קרטזית של הטבלאות )4 שורות(. כעת, מכיוון שאף שורה לא נפלה, אין צורך בביצוע ריפוד עם ערכי.NULL a b b c 1 a b 3 1 a c 4 2 b b 3 2 b c 4 מסקנה: יש משמעות למיקום התנאי, נוכל לראות שהתוצאות שונות אם התנאי מופיע בפקודת ה ON או בפקודת ה USING לעומת התוצאה שתתקבל אם יופיע בתנאי ה.WHERE 2
פקודות :DML בשיעורים האחרונים עסקנו בפקודות DML הנוגעות בנתונים וראינו שיש פקודות העוסקות בשליפה, הוספה, עדכון ומחיקה של נתונים/רשומות בטבלה. עד כה, למדנו את הפקודות הבאות: Insert הכנסת נתונים לטבלה Update עדכון נתונים בטבלה קיימת Delete מחיקת נתונים מטבלה קיימת Select שליפת נתונים השיעור נתחיל ללמוד את החלק השני בשפת ה SQL פקודות DDL העוסקות במבנה. פקודות :DDL )Primary 1( מפתח ראשי Key( מפתח ראשי שדה )או אוסף שדות( המזהה באופן חד ערכי )ומינימאלי( רשומה מסוימת בטבלה. דוגמא 1: מפתח ראשי הבנוי משדה בודד - מספר תעודת זהות בטבלת סטודנטים. StudentID 111 222 333 Students FirstName Avi Dan Ofer LastName Cohen Israeli Bar 3
דוגמא 2: מפתח ראשי הבנוי מאוסף שדות נבנה טבלה המציגה רשימת ספקים ורשימת מוצרים, כאשר נתון: שמות הספקים יהיו: אסם, שטראוס ותנובה המוצרים המיוצרים על ספקים אלו הם: קוטג', קטשופ וגבינה לבנה Vendor Osem Product Ketchup Price 10.00 6.30 5.80 Weight (gr) 1000 מי יהיה שדה המפתח בטבלה? נוכל לראות שלא ניתן להגדיר את הספק כמפתח כי יש ספקים החוזרים על עצמם, על אותו משקל נראה שלא ניתן להגדיר את המוצר כמפתח ראשי כי יש מוצרים בעלי אותו שם לספקים שונים )וכנ"ל לגבי מחיר ומשקל בהם ערכים חוזרים על עצמם(. לכן, הפתרון הוא להגדיר מפתח משולב )מפתח המורכב ממספר שדות( המכיל את השדות ספק+מוצר. שילוב של שדות אלו מבטיח בצורה חד ערכית שהשילוב של ספק+מוצר הינו ייחודי ומינימאלי עבור כל שורה בטבלה. Vendor Osem Product Ketchup Price 10.00 6.30 5.80 Weight (gr) 1000 הערות כפילות ערכים בשדה מפתח )בהמשך לדוגמא הקודמת( - אם מפתח ראשי מורכב מיותר משדה אחד )כמו בדוגמא לעיל(, אזי ערכי אחד השדות יכולים להיות כפולים בתוך עמודה נתונה )לדוגמא: בעמודת ספק נוכל לראות שתנובה מופיעה מספר פעמים( אבל השילוב של כל שדות המפתח הראשי חייבים להיות ייחודיים ברמת טבלה. 4
הוספת אילוץ בשלב יצירת טבלה כפי שלמדנו עד היום, שאנו באים ליצור טבלה חדשה עלינו להגדיר עבור כל טבלה את השדות )העמודות( שירכיבו את הסכמה של הטבלה לעתיד. במהלך בניית טבלה חדשה אנו יכולים בנוסף לשם העמודה העתידי ולסוג העמודה )type( להוסיף גם אילוץ עבור כל עמודה המוגדרת בסכמה. מבנה שורה בפקודת Create יוכל להכיל את המבנה הבא: Column Name Type Constraint לדוגמא: ID int NOT NULL הגדרת מפתח ראשי הגדרת מפתח ראשי - אנו נגדיר את המפתח הראשי בטבלה בשלב של יצירת הטבלה ע"י הוספת הפקודה. והשדות שמרכיבים את המפתח. *** הערה, בעקרון בטבלה יוצג מספר הספק וקוד המוצר ולא השמות שלהם, אך בדוגמא זו על מנת להבהיר את הנקודה הוצגו הנתונים בשמותיהם ולא בקודים המסמלים אותם. *** CREATE TABLE Example ( Vendor TEXT NOT NULL, Product TEXT NOT NULL, Price FLOAT NOT NULL, Weight FLOAT, PRIMARY KEY (Vendor, Product) ); כמות מפתחות - כל טבלה יכולה שיהיה לה רק מפתח ראשי אחד )שיכול להיות מורכב ממספר שדות( והוא אינו יכול להכיל ערכי NULL מכיוון ששדות המפתח חייבים להכיל ערכים ייחודים. מניעת חזרות ע"י הגדרת מפתח ראשי אנו בעצם מונעים אפשרות של הכנסת שורות כפולות לתוך אותה טבלה. ע"י הגדרת מפתח ראשי, ה DBMS הוא זה שמונע מצב של הכנסת שורה כפולה. 5
)2 מפתח זר / חיצוני Key( )Foreign מפתח זר שדה )או אוסף שדות( המצביע על מפתח ראשי בטבלה אחרת. מפתח זר הינו שדה )עמודה( בטבלה אשר ערכיו האפשריים )Domain( נשאבים משדה מקביל בטבלה אחרת אשר בה הוא משמש כמפתח ראשי. ערכי המפתח הזר אינם בלעדיים Unique( )Not בטבלת הבן ויכולים לחזור על עצמם )לדוגמא שדה מספר סטודנט(. דוגמא: קיימת טבלת סטודנטים שבה כל סטודנט משוייך למחלקה בה הוא לומד, כמו כן קיימת טבלת מחלקות המכילה נתונים על כל מחלקה בפקולטה למדעים מדוייקים. ניתן לראות שבכל טבלה יש מפתח ראשי ובמקביל בטבלת סטודנטים עמודת המחלקה מהווה מפתח זר לטבלת מחלקות )כיוון ששדה זה מהווה מפתח ראשי בטבלת מחלקות(. StudentID 111 222 333 FirstName Avi Dan Ofer Students LastName Cohen Israeli Bar Foreign Key Computers s NumberOfCoures 40 52 48 NumberOfStudents 60 720 140 Building A C B נוכל לראות שבהפניה של מפתח זר, נוצר קישור )לינק( בין 2 טבלאות )בירוק( כאשר בצד אחד מופיע שדה המהווה מפתח ראשי בטבלה אחת )מוקף בכתום( שדה זה הופך להיות מפתח זר בטבלת השנייה )מוקף באדום(. 6
הערות מטרה נוספת של מפתח זר היא שמירה על שלמות הנתונים integrity[,]data הכוונה בכך היא שניתן להגדיר קשר זה כאילוץ )Constraint( בהגדרת הטבלה, כך שמערכת ניהול בסיס הנתונים )DBMS( תמנע מצב שיוכנסו ערכים בשדה המפתח הזר שאינם עונים לאילוץ, כלומר אינם נמצאים בטבלת האב. כתוצאה מהגדרת אילוץ כזה, לא נוכל למחוק רשומה מטבלת האב כל עוד ישנן רשומות בטבלת הבן המכילות את מפתח הרשומה כמפתח זר. בשורה התחתונה: על ידי שימוש במפתח זר מגדירים, ולמעשה יוצרים, את הקשרים בין הטבלאות השונות בבסיס הנתונים. לדוגמא: נניח שהיינו רוצים למחוק את מחלקת מתמטיקה מתוך טבלת מחלקות, מחיקה מסוג זה תיצור בעיה לאור העובדה שקיים סטודנט )222( ששייך למחלקה זו )בטבלת סטודנטים( ולכן בשלב המחיקה מטבלת מחלקות, המפתח הזר יגרור את הופעתה של הודעת שגיאה המונעת את מחיקת שורה זו מטבלת מלקות אלא אם קודם לכן נמחק את הסטודנט השייך למחלקה זו )שזו כמובן בקשה הגיונית לאור העובדה שאנו מתכוונים למחוק את המחלקה מהמאגר והגיוני שנוכל למחוק אותה רק אם אין בה סטודנטים(. StudentID 111 222 333 FirstName Avi Dan Ofer Students LastName Cohen Israeli Bar Foreign Key Computers s NumberOfCoures 40 52 48 NumberOfStudents 60 720 140 Building A C B 7